﻿using SharpCompress.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Util
{
    public class FileUtil
    {

        public static Dictionary<string, FileInfo> filelist = new Dictionary<string, FileInfo>();
        private static FileUtil instance;
        private FileUtil() { }

        static FileUtil()
        {
            instance = new FileUtil();
        }

        private static object loglock = new object();

        public static FileUtil GetInstance { get { return instance; } }

        /// <summary>
        /// 编码方式
        /// </summary>
        private static readonly Encoding DefaultEncoding = Encoding.UTF8;

        /// <summary>
        /// 移动文件到另一个文件
        /// </summary>
        /// <param name="sourePath"></param>
        /// <param name="currPath"></param>
        public static void FileMove(string sourePath, string currPath)
        {
            sourePath = sourePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            currPath = currPath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            DirectoryInfo directoryInfo = new DirectoryInfo(sourePath);
            FileInfo[] files = directoryInfo.GetFiles();
            if (!ExistsDir(currPath))
                CreateDirectory(currPath);

            foreach (FileInfo file in files)
            {
                if (!Exists(currPath + "/" + file.Name))
                    file.MoveTo(Path.Combine(currPath, file.Name));
            }
        }

        /// <summary>
        /// 复制一个文件夹下的文件到另一个文件夹
        /// </summary>
        /// <param name="sourePath"></param>
        /// <param name="currPath"></param>
        public static void FileCopyByDirectory(string sourePath, string currPath)
        {
            sourePath = sourePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            currPath = currPath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            DirectoryInfo directoryInfo = new DirectoryInfo(sourePath);
            FileInfo[] files = directoryInfo.GetFiles();
            if (!ExistsDir(currPath))
                CreateDirectory(currPath);

            foreach (FileInfo file in files)
            {
                if (!Exists(currPath + "/" + file.Name))
                    file.CopyTo(Path.Combine(currPath, file.Name));
            }
        }

        /// <summary>
        /// 复制文件到当前目录改名字
        /// </summary>
        /// <param name="oldFile"></param>
        /// <param name="currPath"></param>
        public static void FileCopy(string oldFile, string newFile)
        {
            oldFile = oldFile.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            newFile = newFile.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (File.Exists(oldFile))
            {
                File.Copy(oldFile, newFile); // 使用File类的静态方法Copy来复制文件
            }
        }

        /// <summary>
        /// 判断文件是否存在
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static bool Exists(string filePath)
        {
            filePath = filePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            return File.Exists(filePath);
        }

        /// <summary>
        /// 判断文件夹是否存在
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static bool ExistsDir(string filePath)
        {
            filePath = filePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            return Directory.Exists(filePath);
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool CreateDirectory(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (!FileUtil.Exists(path))
                Directory.CreateDirectory(path);

            return true;
        }

        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool CreateFile(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (!FileUtil.Exists(path))
                File.Create(path);

            return true;
        }

        /// <summary>
        /// 获取指定目录文件夹下所有文件路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<string> GetFileListPath(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            List<string> list = new List<string>();
            if (Directory.Exists(path))
            {
                string[] files = Directory.GetFiles(path);
                foreach (var file in files)
                {
                    list.Add(file);
                }
            }
            return list;
        }

        /// <summary>
        /// 递归获取文件夹文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static Dictionary<string, FileInfo> GetFileList(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            Dictionary<string, FileInfo> list = new Dictionary<string, FileInfo>();
            if (Directory.Exists(path))
            {
                string[] files = Directory.GetFiles(path);
                foreach (var file in files)
                {
                    var extension = Path.GetExtension(file);
                    if (extension != null)
                        list.Add(path, new FileInfo(file));
                }
                string[] dirs = Directory.GetDirectories(path);
                foreach (var dir in dirs)
                    GetFileList(dir);
            }
            return list;
        }

        /// <summary>
        /// 递归获取文件夹文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<FileInfo> GetFileListb(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            List<FileInfo> list = new List<FileInfo>();
            if (Directory.Exists(path))
            {
                string[] files = Directory.GetFiles(path);
                foreach (var file in files)
                {
                    var extension = Path.GetExtension(file);
                    if (extension != null)
                        list.Add(new FileInfo(file));
                }
                string[] dirs = Directory.GetDirectories(path);
                foreach (var dir in dirs)
                    GetFileListb(dir);
            }
            return list;
        }

        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string ReadFile(string filePath)
        {
            filePath = filePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            return ReadFile(filePath, DefaultEncoding);
        }

        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string ReadFile(string filePath, Encoding encoding)
        {
            filePath = filePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            using (var sr = new StreamReader(filePath, encoding))
            {
                return sr.ReadToEnd();
            }
        }

        /// <summary>
        /// 创建目录
        /// </summary>
        /// <param name="modulename"></param>
        /// <returns></returns>
        private string CreateDirectory(string initmodule, string modulename)
        {
            string[] mns = modulename.Split('-');
            if (mns.Length == 1)
            {
                var filedir = (initmodule + modulename).Replace("\\", "/"); // Linux系统部署路径需要改成这样
                if (!Directory.Exists(filedir))
                    Directory.CreateDirectory(filedir);

                return filedir;
            }
            else
            {
                var newnm = string.Empty;
                var filedir = string.Empty;
                foreach (var mn in mns)
                {
                    newnm += mn + "\\";
                    filedir = (initmodule + newnm).Replace("\\", "/"); // Linux系统部署路径需要改成这样
                    if (!Directory.Exists(filedir))
                        Directory.CreateDirectory(filedir);
                }
                newnm = newnm.Substring(0, newnm.Length - 1);
                filedir = (initmodule + newnm).Replace("\\", "/"); // Linux系统部署路径需要改成这样
                return filedir;
            }
        }

        /// <summary>
        /// 写入内容
        /// </summary>
        /// <param name="module"></param>
        /// <param name="content"></param>
        /// <param name="isSuccess"></param>
        public void WriteLog(string module, string content, bool isSuccess)
        {
            var timepath = AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\" + DateTime.Now.ToString("yyyyMMdd");
            timepath = timepath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (!Directory.Exists(timepath))
            {
                Directory.CreateDirectory(timepath);
                WriteLog(module, content, isSuccess);
            }
            else
            {
                var filepath = CreateDirectory(timepath + "\\", module);
                if (!string.IsNullOrEmpty(content))
                {
                    var filetime = isSuccess == true ? "成功" : "失败";
                    var newfilepath = filepath + "\\" + filetime + ".txt";
                    WriteContentToFile(newfilepath, content, isSuccess);
                }
            }
        }

        /// <summary>
        /// 写入内容到文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="content"></param>
        private static void WriteContentToFile(string path, string content, bool newLine)
        {
            lock (loglock)
            {
                try
                {
                    path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
                    Encoding encode = Encoding.UTF8;
                    content = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "  " + content;
                    if (File.Exists(path))
                    {
                        var olddatalength = ReadFileLines(path);
                        if (olddatalength == 0)//文件没有存在内容
                        {
                            using (var file = new FileStream(path, FileMode.OpenOrCreate))
                            {
                                byte[] data = encode.GetBytes(content);
                                file.Write(data, 0, data.Length);
                            }
                        }
                        else//追加内容到原有文件
                        {
                            using (var file = new FileInfo(path).AppendText())
                            {
                                if (newLine)
                                {
                                    if (olddatalength == 1)
                                        file.WriteLine("");

                                    file.WriteLine("");
                                    file.WriteLine(content);
                                }
                                else
                                {
                                    file.Write(content);
                                }
                            }
                        }
                    }
                    else//创建新文件并写入内容
                    {
                        using (var file = new FileStream(path, FileMode.OpenOrCreate))
                        {
                            byte[] data = encode.GetBytes(content);
                            file.Write(data, 0, data.Length);
                        }
                    }
                }
                catch
                {
                    if (!string.IsNullOrEmpty(content))
                        WriteContentToFile(path, content, newLine);
                }
            }
        }

        /// <summary>
        /// 读取文件内容长度
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static int ReadFileLines(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            string content = null;
            using (var stream = new StreamReader(path, Encoding.UTF8))
            {
                content = stream.ReadToEnd();
            }
            return content.Length;
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="path"></param>
        public static void DelFile(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (File.Exists(path))
                File.Delete(path);
        }

        /// <summary>
        /// 复制文件夹（及文件夹下所有子文件夹和文件）
        /// </summary>
        /// <param name="sourcePath">待复制的文件夹路径</param>
        /// <param name="destinationPath">目标路径</param>
        public static void CopyDirectory(String sourcePath, String destinationPath)
        {
            sourcePath = sourcePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            destinationPath = destinationPath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            var info = new DirectoryInfo(sourcePath);
            Directory.CreateDirectory(destinationPath);
            foreach (FileSystemInfo fsi in info.GetFileSystemInfos())
            {
                String destName = Path.Combine(destinationPath, fsi.Name);

                if (fsi is FileInfo) //如果是文件，复制文件
                    File.Copy(fsi.FullName, destName);
                else //如果是文件夹，新建文件夹，递归
                {
                    Directory.CreateDirectory(destName);
                    CopyDirectory(fsi.FullName, destName);
                }
            }
        }

        /// <summary>
        ///  删除文件夹（及文件夹下所有子文件夹和文件）
        /// </summary>
        /// <param name="directoryPath"></param>
        public static void DeleteFolder(string directoryPath)
        {
            directoryPath = directoryPath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            foreach (string d in Directory.GetFileSystemEntries(directoryPath))
            {
                if (File.Exists(d))
                {
                    var fi = new FileInfo(d);
                    if (fi.Attributes.ToString().IndexOf("ReadOnly", StringComparison.Ordinal) != -1)
                        fi.Attributes = FileAttributes.Normal;
                    File.Delete(d); //删除文件   
                }
                else
                    DeleteFolder(d); //删除文件夹
            }
            Directory.Delete(directoryPath); //删除空文件夹
        }

        /// <summary>
        ///  清空文件夹（及文件夹下所有子文件夹和文件）
        /// </summary>
        /// <param name="directoryPath"></param>
        public static void ClearFolder(string directoryPath)
        {
            directoryPath = directoryPath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            foreach (string d in Directory.GetFileSystemEntries(directoryPath))
            {
                if (File.Exists(d))
                {
                    var fi = new FileInfo(d);
                    if (fi.Attributes.ToString().IndexOf("ReadOnly", StringComparison.Ordinal) != -1)
                        fi.Attributes = FileAttributes.Normal;
                    File.Delete(d); //删除文件   
                }
                else
                    DeleteFolder(d); //删除文件夹
            }
        }

        /// <summary>
        /// 取得文件大小，按适当单位转换
        /// </summary>
        /// <param name="filepath"></param>
        /// <returns></returns>
        public static string GetFileSize(string filepath)
        {
            filepath = filepath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            string result = "0KB";
            if (File.Exists(filepath))
            {
                var size = new FileInfo(filepath).Length;
                int filelength = size.ToString().Length;
                if (filelength < 4)
                    result = size + "byte";
                else if (filelength < 7)
                    result = Math.Round(Convert.ToDouble(size / 1024d), 2) + "KB";
                else if (filelength < 10)
                    result = Math.Round(Convert.ToDouble(size / 1024d / 1024), 2) + "MB";
                else if (filelength < 13)
                    result = Math.Round(Convert.ToDouble(size / 1024d / 1024 / 1024), 2) + "GB";
                else
                    result = Math.Round(Convert.ToDouble(size / 1024d / 1024 / 1024 / 1024), 2) + "TB";
                return result;
            }
            return result;
        }

        /// <summary>
        /// 返回文件或者文件夹最后更新的时间
        /// </summary>
        /// <param name="filePath">文件目录</param>
        /// <returns></returns>
        public static DateTime? GetUpdateTime(string filePath)
        {
            filePath = filePath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (File.Exists(filePath))
            {
                return new FileInfo(filePath).LastWriteTime;
            }
            return null;
        }


        public static string GetFileName(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (File.Exists(path))
            {
                return System.IO.Path.GetFileName(path);
            }
            else
            { return null; }
        }


        /// <summary>
        /// 获取GUID
        /// </summary>
        /// <returns></returns>
        public static long GenerateGuid()
        {
            byte[] buffer = Guid.NewGuid().ToByteArray();
            return BitConverter.ToInt64(buffer, 0);
        }

        /// <summary>
        /// 通过迭代器读取txt日志内容
        /// </summary>
        /// <param name="fullPath"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <param name="seekEnd"></param>
        /// <returns></returns>
        public static IEnumerable<string> ReadPageLine(string fullPath, int page, int pageSize, bool seekEnd = false)
        {
            fullPath = fullPath.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (page <= 0)
            {
                page = 1;
            }
            fullPath = fullPath.ReplacePath();
            var lines = File.ReadLines(fullPath, Encoding.UTF8);
            if (seekEnd)
            {
                int lineCount = lines.Count();
                int linPageCount = (int)Math.Ceiling(lineCount / (pageSize * 1.00));
                //超过总页数，不处理
                if (page > linPageCount)
                {
                    page = 0;
                    pageSize = 0;
                }
                else if (page == linPageCount)//最后一页，取最后一页剩下所有的行
                {
                    pageSize = lineCount - (page - 1) * pageSize;
                    if (page == 1)
                    {
                        page = 0;
                    }
                    else
                    {
                        page = lines.Count() - page * pageSize;
                    }
                }
                else
                {
                    page = lines.Count() - page * pageSize;
                }
            }
            else
            {
                page = (page - 1) * pageSize;
            }
            lines = lines.Skip(page).Take(pageSize);

            var enumerator = lines.GetEnumerator();
            int count = 1;
            while (enumerator.MoveNext() || count <= pageSize)
            {
                yield return enumerator.Current;
                count++;
            }
            enumerator.Dispose();
        }

        public static string ReadFileb(string path)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            path = path.ReplacePath();
            if (!File.Exists(path))
                return "";
            using (StreamReader stream = new StreamReader(path))
            {
                return stream.ReadToEnd(); // 读取文件
            }
        }

        /// <summary>
        /// 写文件
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="Strings">文件内容</param>
        public static void WriteFile(string path, string fileName, string content, bool appendToLast = false)
        {
            path = path.Replace("\\", "/"); // Linux系统部署路径需要改成这样
            if (!path.EndsWith("\\"))
            {
                path = path + "\\";
            }
            path = path.ReplacePath();
            if (!Directory.Exists(path))//如果不存在就创建file文件夹
            {
                Directory.CreateDirectory(path);
            }
            using (FileStream stream = File.Open(path + fileName, FileMode.OpenOrCreate, FileAccess.Write))
            {
                byte[] by = Encoding.Default.GetBytes(content);
                if (appendToLast)
                {
                    stream.Position = stream.Length;
                }
                else
                {
                    stream.SetLength(0);
                }
                stream.Write(by, 0, by.Length);
            }
        }
    }
}
